package com.miniapp.framework.web.service;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.miniapp.basics.manager.WxMaServiceManager;
import com.miniapp.basics.mapper.MiniAppUserMapper;
import com.miniapp.basics.service.IMiniAppService;
import com.miniapp.basics.service.IMiniAppUserService;
import com.miniapp.common.core.domain.entity.miniapp.MiniApp;
import com.miniapp.common.core.domain.entity.miniapp.MiniAppUser;
import com.miniapp.common.core.domain.model.LoginUser;
import com.miniapp.common.core.domain.model.miniapp.WxLoginBody;
import com.miniapp.common.core.domain.model.miniapp.WxLoginUser;
import com.miniapp.common.core.redis.RedisCache;
import com.miniapp.common.enums.DeleteFlag;
import com.miniapp.common.enums.StopFlag;
import com.miniapp.common.exception.MiniAppException;
import com.miniapp.common.exception.ServiceException;
import com.miniapp.common.gen.domain.PaicFtiAgent;
import com.miniapp.common.gen.domain.PaicFtiAgentExample;
import com.miniapp.common.gen.domain.TMiniAgent;
import com.miniapp.common.gen.domain.TMiniAgentExample;
import com.miniapp.common.gen.mapper.PaicFtiAgentMapper;
import com.miniapp.common.gen.mapper.TMiniAgentMapper;
import com.miniapp.common.utils.StringUtils;
import com.miniapp.common.utils.sign.Md5Utils;
import com.miniapp.framework.security.context.AuthenticationContextHolder;
import com.miniapp.framework.security.miniapp.MiniAppByOpenIdAuthenticationToken;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.formula.functions.T;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class MiniAppLoginService
{
    @Autowired
    private IMiniAppService miniAppService;

    @Autowired
    private IMiniAppUserService miniAppUserService;

    @Autowired
    private WxMaServiceManager wxMaServiceManager;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private MiniAppUserMapper miniAppUserMapper;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisCache redisCache;

    /**
     * 小程序默认密码
     */
    public static final String DEFAULT_MINI_APP_PASSWORD = "123456";

    public static final String MINI_APP_PASSWORD_SALT = "RUONJ8165";

    public static final String PHONE_LOGIN_ALL_TOKEN = "phone_login_all_token_";

    public JSONObject wxMiniLogin(WxLoginBody wxLoginBody) throws MiniAppException
    {
        JSONObject data = new JSONObject();
        MiniApp miniApp = miniAppService.selectMiniAppByAppid(wxLoginBody.getAppid());
        if(ObjectUtils.isEmpty(miniApp))
        {
            throw new MiniAppException("appid error");
        }
        WxMaService wxMaService = wxMaServiceManager.getWxMaService(wxLoginBody.getAppid());
        // 小程序用户验证
        Authentication authentication = null;
        try
        {
            WxMaJscode2SessionResult sessionResult = wxMaService.jsCode2SessionInfo(wxLoginBody.getCode());
            insertMiniAppUser(sessionResult.getOpenid(),miniApp.getId());
            MiniAppByOpenIdAuthenticationToken miniAppByOpenIdAuthenticationToken = new MiniAppByOpenIdAuthenticationToken(sessionResult.getOpenid() + "," +  miniApp.getId());
            AuthenticationContextHolder.setContext(miniAppByOpenIdAuthenticationToken);
            authentication = authenticationManager.authenticate(miniAppByOpenIdAuthenticationToken);

        }
        catch (Exception e)
        {
            log.error("---------------wxMiniLogin fail",e);
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        //设置手机号
        setMiniAppUserPhone(loginUser);
        //设置有没有平安货运险出单权限
        setMiniAppUserPaicftiAuth(loginUser.getMiniAppUser());
        String token = tokenService.createToken(loginUser);
        data.put("token", token);
        return data;
    }


    /**
     * 用户名密码登录
     * @param wxLoginBody
     * @return
     * @throws MiniAppException
     */
    public JSONObject wxMiniLoginPassWord(WxLoginBody wxLoginBody) throws MiniAppException
    {

        String userPhone = wxLoginBody.getUserPhone();
        String inputPassWord = wxLoginBody.getPassWord();
        String md5Password = Md5Utils.hash(inputPassWord + MINI_APP_PASSWORD_SALT);

        MiniAppUser queryMiniAppUser = new MiniAppUser();
        queryMiniAppUser.setPurePhoneNumber(userPhone);
        List<MiniAppUser> miniAppUserList = miniAppUserService.selectMiniAppUserList(queryMiniAppUser);
        if(CollectionUtils.isEmpty(miniAppUserList)){
            throw new ServiceException("手机号不存在");
        }
        log.info("通过手机号查询到{}个用户",miniAppUserList.size());

        MiniAppUser miniAppUser = miniAppUserList.get(0);
        String passWord = miniAppUser.getPassword();

        if(!md5Password.equals(passWord)){
            throw new ServiceException("密码错误");
        }
        log.info("手机号登录{}，密码验证成功",userPhone);

        JSONObject data = new JSONObject();
        MiniApp miniApp = miniAppService.selectMiniAppByAppid(wxLoginBody.getAppid());
        if(ObjectUtils.isEmpty(miniApp))
        {
            throw new MiniAppException("appid error");
        }
        WxMaService wxMaService = wxMaServiceManager.getWxMaService(wxLoginBody.getAppid());
        // 小程序用户验证
        Authentication authentication = null;
        try
        {
            WxMaJscode2SessionResult sessionResult = wxMaService.jsCode2SessionInfo(wxLoginBody.getCode());
            MiniAppByOpenIdAuthenticationToken miniAppByOpenIdAuthenticationToken = new MiniAppByOpenIdAuthenticationToken(sessionResult.getOpenid() + "," +  miniApp.getId());
            AuthenticationContextHolder.setContext(miniAppByOpenIdAuthenticationToken);
            authentication = authenticationManager.authenticate(miniAppByOpenIdAuthenticationToken);
        }
        catch (Exception e)
        {
            log.error("---------------wxMiniLogin fail",e);
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        log.info("开始设置用户信息里的手机号手机号");
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        loginUser.getMiniAppUser().setPurePhoneNumber(userPhone);


        //设置有没有平安货运险出单权限
        setMiniAppUserPaicftiAuth(loginUser.getMiniAppUser());
        String token = tokenService.createToken(loginUser);
        data.put("token", token);
        log.info("用户出单权限设置成功");

        log.info("开始添加手机号、密码登录对应的token");
        //存入缓存中，在修改密码时删除全部token
        Boolean aBoolean = redisCache.hasKey(PHONE_LOGIN_ALL_TOKEN + userPhone);
        if(aBoolean){
            Set<String> cacheSet = redisCache.getCacheSet(PHONE_LOGIN_ALL_TOKEN + userPhone);
            cacheSet.add(loginUser.getToken());
            redisCache.setCacheSet(PHONE_LOGIN_ALL_TOKEN + userPhone,cacheSet);
            log.info("设置手机号对应的token成功");
        }else {
            Set<String> cacheSet = new HashSet<>();
            cacheSet.add(loginUser.getToken());
            redisCache.setCacheSet(PHONE_LOGIN_ALL_TOKEN + userPhone,cacheSet);
            log.info("第一次设置手机号对应的token成功");
        }
        return data;

    }




    private void insertMiniAppUser(String openId,Long miniAppId)
    {
        try
        {
            MiniAppUser miniAppUser = new MiniAppUser();
            miniAppUser.setMiniAppId(miniAppId);
            miniAppUser.setOpenId(openId);
            miniAppUser.setNickName("微信用户" + openId.substring(openId.length()-3));
            //设置默认密码
            String defaultPassword = Md5Utils.hash(DEFAULT_MINI_APP_PASSWORD + MINI_APP_PASSWORD_SALT);
            miniAppUser.setPassword(defaultPassword);
            miniAppUserService.insertMiniAppUser(miniAppUser);
        }
        catch (DuplicateKeyException e)
        {
            log.error("用户已经存在,无需重复添加,openId:{},miniAppId:{}",openId,miniAppId);
        }
    }

    public static void main(String[] args) {
        String defaultPassword = Md5Utils.hash(DEFAULT_MINI_APP_PASSWORD + MINI_APP_PASSWORD_SALT);
        System.out.println(defaultPassword);
    }


    /**
     * 绑定手机号
     * @param wxLoginBody
     * @return
     */
    public JSONObject bindPhoneNumber( WxLoginBody wxLoginBody,LoginUser loginUser){
        JSONObject jsonObject = new JSONObject();
        String miniAppUserPurePhoneNumber = loginUser.getMiniAppUser().getPurePhoneNumber();
        if(StringUtils.isNotBlank(miniAppUserPurePhoneNumber)){
            log.info("用户已经绑定过手机号直接返回手机号：{}",miniAppUserPurePhoneNumber);
            jsonObject.put("phoneNumber",miniAppUserPurePhoneNumber);
            return jsonObject;
        }

        WxMaService wxMaService = wxMaServiceManager.getWxMaService(wxLoginBody.getAppid());
        try {
            WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(wxLoginBody.getCode());
            if(phoneNoInfo != null){
                String purePhoneNumber = phoneNoInfo.getPurePhoneNumber();
                log.info("获取到手机号为：{}",purePhoneNumber);
                //设置到缓存中
                MiniAppUser miniAppUser = loginUser.getMiniAppUser();
                miniAppUser.setPurePhoneNumber(purePhoneNumber);
                //设置有没有平安货运险出单权限
                setMiniAppUserPaicftiAuth(loginUser.getMiniAppUser());
                tokenService.setLoginUser(loginUser);

                //更新数据库
                Long miniAppUserId = loginUser.getMiniAppUser().getId();
                log.info("要更新的小程序用户id为：{}",miniAppUserId);
                MiniAppUser newMiniAppUser = miniAppUserMapper.selectMiniAppUserById(miniAppUserId);
                newMiniAppUser.setPurePhoneNumber(purePhoneNumber);
                miniAppUserMapper.updateMiniAppUser(newMiniAppUser);

                jsonObject.put("phoneNumber",purePhoneNumber);
                return jsonObject;
            }else {
                log.info("获取手机号失败:返回为空");
                return jsonObject;
            }
        } catch (WxErrorException e) {
            e.printStackTrace();
            return jsonObject;
        }


    }

    /**
     * 设置手机号
     * @param loginUser
     */
    private void setMiniAppUserPhone(LoginUser loginUser){
        MiniAppUser loginMiniAppUser = loginUser.getMiniAppUser();
        MiniAppUser miniAppUser = miniAppUserMapper.selectMiniAppUserById(loginMiniAppUser.getId());
        String purePhoneNumber = miniAppUser.getPurePhoneNumber();
        loginMiniAppUser.setPurePhoneNumber(purePhoneNumber);


    }

    @Autowired
    private TMiniAgentMapper tMiniAgentMapper;

    /**
     * 设置平安货运险出单权限
     * @param miniAppUser
     */
    public void setMiniAppUserPaicftiAuth(MiniAppUser miniAppUser){

        String purePhoneNumber = miniAppUser.getPurePhoneNumber();
        if(StringUtils.isBlank(purePhoneNumber)){
            miniAppUser.setPaicftiAuth(false);
            return;
        }
        TMiniAgentExample tMiniAgentExample = new TMiniAgentExample();
        tMiniAgentExample.createCriteria()
                .andAgentPhoneEqualTo(purePhoneNumber)
                .andDelFlagEqualTo(DeleteFlag.NO_DELETED.getCode())
                .andStopFlagEqualTo(StopFlag.NO_DISABLE.getCode());
        List<TMiniAgent> tMiniAgentList = tMiniAgentMapper.selectByExample(tMiniAgentExample);
        if(CollectionUtils.isEmpty(tMiniAgentList)){
            miniAppUser.setPaicftiAuth(false);
        }else {
            miniAppUser.setPaicftiAuth(true);
        }

//        PaicFtiAgentExample paicFtiAgentExample = new PaicFtiAgentExample();
//        paicFtiAgentExample.createCriteria().andAgentPhoneEqualTo(purePhoneNumber);
//        List<PaicFtiAgent> paicFtiAgentList = paicFtiAgentMapper.selectByExample(paicFtiAgentExample);
//        if(CollectionUtils.isEmpty(paicFtiAgentList)){
//            miniAppUser.setPaicftiAuth(false);
//        }else {
//            miniAppUser.setPaicftiAuth(true);
//        }


    }


}
